import type { StringKeyObject } from 'my-ts-core/types';

import { WebSocketConnectionState } from './web-socket-connection-state';

/**
 * https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
 *
 * async function connect(): Promise<void> {
 *   await WebSocketClient.connect('ws://127.0.0.1:8089/hello-websocket/ws');
 *
 *   WebSocketClient.listen((msg: any) => {
 *     console.dir(msg);
 *   });
 * }
 *
 * function send(): void {
 *   WebSocketClient.send({ id: 1, name: 'User' });
 * }
 *
 * function disconnect(): void {
 *   WebSocketClient.disconnect();
 * }
 */
export class WebSocketClient {
  protected static currentStateValue: WebSocketConnectionState =
    WebSocketConnectionState.Disconnected;
  protected static webSocket: WebSocket;

  get currentState(): WebSocketConnectionState {
    return WebSocketClient.currentStateValue;
  }

  async connect(url: string, protocols?: string[]): Promise<void> {
    return new Promise((resolve) => {
      WebSocketClient.webSocket = new WebSocket(url, protocols);

      WebSocketClient.webSocket.onopen = () => {
        WebSocketClient.currentStateValue = WebSocketConnectionState.Connected;
        return resolve();
      };

      WebSocketClient.webSocket.onclose = (): void => {
        WebSocketClient.currentStateValue = WebSocketConnectionState.Disconnected;
      };
    });
  }

  disconnect(): void {
    if (WebSocketClient.currentStateValue == WebSocketConnectionState.Connected) {
      WebSocketClient.webSocket.close();
    }
  }

  listen(onListen: (msg: any) => void): void {
    WebSocketClient.webSocket.onmessage = (ev: MessageEvent) => {
      onListen.call(this, ev.data);
    };
  }

  send(data: StringKeyObject): void {
    WebSocketClient.webSocket?.send(JSON.stringify(data));
  }
}
